<template>
  <div class="error-boundary">
    <slot v-if="!hasError" />
    
    <!-- 错误状态 -->
    <div v-else class="error-content">
      <div class="error-icon">
        <el-icon><Warning /></el-icon>
      </div>
      
      <div class="error-info">
        <h3>{{ errorTitle }}</h3>
        <p>{{ errorMessage }}</p>
        
        <div v-if="showDetails && errorDetails" class="error-details">
          <el-collapse>
            <el-collapse-item title="错误详情" name="details">
              <pre>{{ errorDetails }}</pre>
            </el-collapse-item>
          </el-collapse>
        </div>
        
        <div class="error-actions">
          <el-button type="primary" @click="handleRetry">
            <el-icon><Refresh /></el-icon>
            重试
          </el-button>
          <el-button @click="handleReload">
            <el-icon><RefreshRight /></el-icon>
            刷新页面
          </el-button>
          <el-button v-if="showReport" @click="handleReport">
            <el-icon><Warning /></el-icon>
            报告问题
          </el-button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onErrorCaptured, onMounted } from 'vue'
import { Warning, Refresh, RefreshRight } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'

// Props
const props = defineProps({
  // 自定义错误标题
  title: {
    type: String,
    default: '页面出现错误'
  },
  // 自定义错误消息
  message: {
    type: String,
    default: '抱歉，页面遇到了一些问题，请稍后重试。'
  },
  // 是否显示错误详情
  showDetails: {
    type: Boolean,
    default: false
  },
  // 是否显示报告按钮
  showReport: {
    type: Boolean,
    default: true
  },
  // 是否自动重试
  autoRetry: {
    type: Boolean,
    default: false
  },
  // 自动重试次数
  maxRetries: {
    type: Number,
    default: 3
  },
  // 重试间隔（毫秒）
  retryDelay: {
    type: Number,
    default: 2000
  }
})

// Emits
const emit = defineEmits(['error', 'retry', 'report'])

// 响应式数据
const hasError = ref(false)
const errorInfo = ref(null)
const retryCount = ref(0)
const retryTimer = ref(null)

// 计算属性
const errorTitle = computed(() => {
  return errorInfo.value?.title || props.title
})

const errorMessage = computed(() => {
  return errorInfo.value?.message || props.message
})

const errorDetails = computed(() => {
  if (!errorInfo.value) return null
  
  return [
    `错误类型: ${errorInfo.value.type || 'Unknown'}`,
    `错误消息: ${errorInfo.value.originalMessage || 'No message'}`,
    `错误堆栈: ${errorInfo.value.stack || 'No stack trace'}`,
    `发生时间: ${new Date().toLocaleString()}`,
    `用户代理: ${navigator.userAgent}`,
    `页面URL: ${window.location.href}`
  ].join('\n')
})

// 错误捕获
onErrorCaptured((error, instance, info) => {
  console.error('ErrorBoundary captured error:', error, info)
  
  hasError.value = true
  errorInfo.value = {
    type: error.name,
    originalMessage: error.message,
    stack: error.stack,
    componentInfo: info,
    instance: instance
  }
  
  emit('error', {
    error,
    instance,
    info,
    errorInfo: errorInfo.value
  })
  
  // 自动重试
  if (props.autoRetry && retryCount.value < props.maxRetries) {
    startAutoRetry()
  }
  
  // 阻止错误继续向上传播
  return false
})

// 全局错误监听
onMounted(() => {
  // 监听未捕获的Promise错误
  window.addEventListener('unhandledrejection', handleUnhandledRejection)
  
  // 监听全局JavaScript错误
  window.addEventListener('error', handleGlobalError)
})

onUnmounted(() => {
  window.removeEventListener('unhandledrejection', handleUnhandledRejection)
  window.removeEventListener('error', handleGlobalError)
  clearTimeout(retryTimer.value)
})

// 方法
const handleUnhandledRejection = (event) => {
  console.error('Unhandled promise rejection:', event.reason)
  
  hasError.value = true
  errorInfo.value = {
    type: 'UnhandledPromiseRejection',
    originalMessage: event.reason?.message || String(event.reason),
    stack: event.reason?.stack || 'No stack trace available'
  }
  
  emit('error', {
    error: event.reason,
    type: 'unhandledrejection',
    errorInfo: errorInfo.value
  })
}

const handleGlobalError = (event) => {
  console.error('Global error:', event.error)
  
  hasError.value = true
  errorInfo.value = {
    type: event.error?.name || 'GlobalError',
    originalMessage: event.error?.message || event.message,
    stack: event.error?.stack || 'No stack trace available',
    filename: event.filename,
    lineno: event.lineno,
    colno: event.colno
  }
  
  emit('error', {
    error: event.error,
    type: 'global',
    errorInfo: errorInfo.value
  })
}

const startAutoRetry = () => {
  retryCount.value++
  
  retryTimer.value = setTimeout(() => {
    handleRetry()
  }, props.retryDelay)
  
  ElMessage.info(`自动重试中... (${retryCount.value}/${props.maxRetries})`)
}

const handleRetry = () => {
  clearTimeout(retryTimer.value)
  
  hasError.value = false
  errorInfo.value = null
  
  emit('retry', {
    retryCount: retryCount.value,
    isAutoRetry: retryCount.value > 0
  })
  
  ElMessage.success('正在重试...')
}

const handleReload = () => {
  window.location.reload()
}

const handleReport = () => {
  const reportData = {
    error: errorInfo.value,
    userAgent: navigator.userAgent,
    url: window.location.href,
    timestamp: new Date().toISOString(),
    userId: 'current-user-id', // 从用户状态获取
    sessionId: 'current-session-id' // 从会话状态获取
  }
  
  emit('report', reportData)
  
  // 这里可以发送错误报告到服务器
  // await errorReportApi.submit(reportData)
  
  ElMessage.success('错误报告已提交，感谢您的反馈！')
}

// 重置错误状态的方法（供外部调用）
const resetError = () => {
  hasError.value = false
  errorInfo.value = null
  retryCount.value = 0
  clearTimeout(retryTimer.value)
}

// 暴露方法给父组件
defineExpose({
  resetError,
  hasError: readonly(hasError),
  errorInfo: readonly(errorInfo)
})
</script>

<style lang="scss" scoped>
.error-boundary {
  width: 100%;
  height: 100%;
}

.error-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 400px;
  padding: 40px 20px;
  text-align: center;
}

.error-icon {
  margin-bottom: 24px;
  
  .el-icon {
    font-size: 64px;
    color: var(--el-color-warning);
  }
}

.error-info {
  max-width: 600px;
  
  h3 {
    font-size: 24px;
    font-weight: 600;
    color: var(--el-text-color-primary);
    margin-bottom: 16px;
  }
  
  p {
    font-size: 16px;
    color: var(--el-text-color-secondary);
    line-height: 1.6;
    margin-bottom: 24px;
  }
}

.error-details {
  margin-bottom: 24px;
  text-align: left;
  
  pre {
    background: var(--el-fill-color-extra-light);
    padding: 16px;
    border-radius: 6px;
    font-size: 12px;
    line-height: 1.4;
    overflow-x: auto;
    white-space: pre-wrap;
    word-break: break-word;
  }
}

.error-actions {
  display: flex;
  gap: 12px;
  justify-content: center;
  flex-wrap: wrap;
  
  @media (max-width: 480px) {
    flex-direction: column;
    align-items: center;
    
    .el-button {
      width: 200px;
    }
  }
}

@media (max-width: 768px) {
  .error-content {
    min-height: 300px;
    padding: 20px;
  }
  
  .error-icon .el-icon {
    font-size: 48px;
  }
  
  .error-info h3 {
    font-size: 20px;
  }
  
  .error-info p {
    font-size: 14px;
  }
}
</style>
